#include <QtGui>

#include <math.h>

#include "renderthread.h"

RenderThread::RenderThread(QObject *parent)
    : QThread(parent), lambda(0, 0)
{
    restart = false;
    abort = false;

    int stepSize = 512/ColormapSize;
    colormap[0] = qRgb(0, 0, 0);
    for (int i = 1; i < ColormapSize/2; ++i) {
        colormap[i] = qRgb(i * stepSize - 1, 0, 0);
    }

    for (int i = ColormapSize/2; i < ColormapSize; ++i) {
        colormap[i] = qRgb(256-(stepSize*i) % 255, 0, 0);
    }
}

RenderThread::~RenderThread()
{
    mutex.lock();
    abort = true;
    condition.wakeOne();
    mutex.unlock();

    wait();
}

void RenderThread::render(int numIterations,
                          const Complex &lambda,
                          const QTransform &inverseMatrix,
                          const QSize &resultSize)
{
    QMutexLocker locker(&mutex);

    this->numIterations = numIterations;
    this->lambda = lambda;
    this->inverseMatrix = inverseMatrix;
    this->resultSize = resultSize;

    if (!isRunning()) {
        start(LowPriority);
    } else {
        restart = true;
        condition.wakeOne();
    }
}

void RenderThread::run()
{
    forever {
        mutex.lock();
        QSize resultSize = this->resultSize;
        QTransform inverseMatrix = this->inverseMatrix;
        Complex lambda = this->lambda;
        int numIterations = this->numIterations;
        mutex.unlock();

        QImage image(resultSize, QImage::Format_RGB32);
        double tx, ty;

        for (int y = 0; y < resultSize.height(); ++y) {
            if (restart)
                break;
            if (abort)
                return;

            uint *scanLine =
                reinterpret_cast<uint *>(image.scanLine(y));

            for (int x = 0; x < resultSize.width(); ++x) {
                inverseMatrix.map(x, y, &tx, &ty);
                int i = pointIteration(Complex(tx, ty), numIterations, lambda);
                *scanLine++ = (i == numIterations) ? 
                    0xff000020 : colormap[i % ColormapSize];
            }
        }

        if (!restart)
            emit renderedImage(image);

        mutex.lock();
        if (!restart)
            condition.wait(&mutex);
        restart = false;
        mutex.unlock();
    }
}
